// /********** Array **********/
// if (!Array.isArray) {
//     Array.isArray = function (arg) {
//         return Object.prototype.toString.call(arg) === '[object Array]';
//     };
// }

// // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
// if (!Array.prototype.findIndex) {
//     Object.defineProperty(Array.prototype, 'findIndex', {
//         value: function (predicate) {
//             // 1. Let O be ? ToObject(this value).
//             if (this == null) {
//                 throw new TypeError('"this" is null or not defined');
//             }

//             var o = Object(this);

//             // 2. Let len be ? ToLength(? Get(O, "length")).
//             var len = o.length >>> 0;

//             // 3. If IsCallable(predicate) is false, throw a TypeError exception.
//             if (typeof predicate !== 'function') {
//                 throw new TypeError('predicate must be a function');
//             }

//             // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
//             var thisArg = arguments[1];

//             // 5. Let k be 0.
//             var k = 0;

//             // 6. Repeat, while k < len
//             while (k < len) {
//                 // a. Let Pk be ! ToString(k).
//                 // b. Let kValue be ? Get(O, Pk).
//                 // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
//                 // d. If testResult is true, return k.
//                 var kValue = o[k];
//                 if (predicate.call(thisArg, kValue, k, o)) {
//                     return k;
//                 }
//                 // e. Increase k by 1.
//                 k++;
//             }

//             // 7. Return -1.
//             return -1;
//         }
//     });
// }

// // https://tc39.github.io/ecma262/#sec-array.prototype.find
// if (!Array.prototype.find) {
//     Object.defineProperty(Array.prototype, 'find', {
//         value: function (predicate) {
//             // 1. Let O be ? ToObject(this value).
//             if (this == null) {
//                 throw new TypeError('"this" is null or not defined');
//             }

//             var o = Object(this);

//             // 2. Let len be ? ToLength(? Get(O, "length")).
//             var len = o.length >>> 0;

//             // 3. If IsCallable(predicate) is false, throw a TypeError exception.
//             if (typeof predicate !== 'function') {
//                 throw new TypeError('predicate must be a function');
//             }

//             // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
//             var thisArg = arguments[1];

//             // 5. Let k be 0.
//             var k = 0;

//             // 6. Repeat, while k < len
//             while (k < len) {
//                 // a. Let Pk be ! ToString(k).
//                 // b. Let kValue be ? Get(O, Pk).
//                 // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
//                 // d. If testResult is true, return kValue.
//                 var kValue = o[k];
//                 if (predicate.call(thisArg, kValue, k, o)) {
//                     return kValue;
//                 }
//                 // e. Increase k by 1.
//                 k++;
//             }

//             // 7. Return undefined.
//             return undefined;
//         }
//     });
// }

// // Production steps of ECMA-262, Edition 5, 15.4.4.18
// // Reference: http://es5.github.io/#x15.4.4.18
// if (!Array.prototype.forEach) {
//     Object.defineProperty(Array.prototype, 'forEach', {
//         value: function (callback, thisArg) {

//             var T, k;

//             if (this == null) {
//                 throw new TypeError(' this is null or not defined');
//             }

//             // 1. Let O be the result of calling toObject() passing the
//             // |this| value as the argument.
//             var O = Object(this);

//             // 2. Let lenValue be the result of calling the Get() internal
//             // method of O with the argument "length".
//             // 3. Let len be toUint32(lenValue).
//             var len = O.length >>> 0;

//             // 4. If isCallable(callback) is false, throw a TypeError exception. 
//             // See: http://es5.github.com/#x9.11
//             if (typeof callback !== 'function') {
//                 throw new TypeError(callback + ' is not a function');
//             }

//             // 5. If thisArg was supplied, let T be thisArg; else let
//             // T be undefined.
//             if (arguments.length > 1) {
//                 T = thisArg;
//             }

//             // 6. Let k be 0
//             k = 0;

//             // 7. Repeat, while k < len
//             while (k < len) {

//                 var kValue;

//                 // a. Let Pk be ToString(k).
//                 //    This is implicit for LHS operands of the in operator
//                 // b. Let kPresent be the result of calling the HasProperty
//                 //    internal method of O with argument Pk.
//                 //    This step can be combined with c
//                 // c. If kPresent is true, then
//                 if (k in O) {

//                     // i. Let kValue be the result of calling the Get internal
//                     // method of O with argument Pk.
//                     kValue = O[k];

//                     // ii. Call the Call internal method of callback with T as
//                     // the this value and argument list containing kValue, k, and O.
//                     callback.call(T, kValue, k, O);
//                 }
//                 // d. Increase k by 1.
//                 k++;
//             }
//             // 8. return undefined
//         }
//     });
// }

// // 实现 ECMA-262, Edition 5, 15.4.4.19
// // 参考: http://es5.github.com/#x15.4.4.19
// if (!Array.prototype.map) {
//     Object.defineProperty(Array.prototype, 'map', {
//         value: function (callback, thisArg) {

//             var T, A, k;

//             if (this == null) {
//                 throw new TypeError(' this is null or not defined');
//             }

//             // 1. 将O赋值为调用map方法的数组.
//             var O = Object(this);

//             // 2.将len赋值为数组O的长度.
//             var len = O.length >>> 0;

//             // 3.如果callback不是函数,则抛出TypeError异常.
//             if (Object.prototype.toString.call(callback) != '[object Function]') {
//                 throw new TypeError(callback + ' is not a function');
//             }

//             // 4. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.
//             if (thisArg) {
//                 T = thisArg;
//             }

//             // 5. 创建新数组A,长度为原数组O长度len
//             A = new Array(len);

//             // 6. 将k赋值为0
//             k = 0;

//             // 7. 当 k < len 时,执行循环.
//             while (k < len) {

//                 var kValue, mappedValue;

//                 //遍历O,k为原数组索引
//                 if (k in O) {

//                     //kValue为索引k对应的值.
//                     kValue = O[k];

//                     // 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
//                     mappedValue = callback.call(T, kValue, k, O);

//                     // 返回值添加到新数组A中.
//                     A[k] = mappedValue;
//                 }
//                 // k自增1
//                 k++;
//             }

//             // 8. 返回新数组A
//             return A;
//         }
//     });
// }

// // https://tc39.github.io/ecma262/#sec-array.prototype.includes
// if (!Array.prototype.includes) {
//     Object.defineProperty(Array.prototype, 'includes', {
//         value: function (searchElement, fromIndex) {

//             // 1. Let O be ? ToObject(this value).
//             if (this == null) {
//                 throw new TypeError('"this" is null or not defined');
//             }

//             var o = Object(this);

//             // 2. Let len be ? ToLength(? Get(O, "length")).
//             var len = o.length >>> 0;

//             // 3. If len is 0, return false.
//             if (len === 0) {
//                 return false;
//             }

//             // 4. Let n be ? ToInteger(fromIndex).
//             //    (If fromIndex is undefined, this step produces the value 0.)
//             var n = fromIndex | 0;

//             // 5. If n ≥ 0, then
//             //  a. Let k be n.
//             // 6. Else n < 0,
//             //  a. Let k be len + n.
//             //  b. If k < 0, let k be 0.
//             var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

//             // 7. Repeat, while k < len
//             while (k < len) {
//                 // a. Let elementK be the result of ? Get(O, ! ToString(k)).
//                 // b. If SameValueZero(searchElement, elementK) is true, return true.
//                 // c. Increase k by 1.
//                 // NOTE: === provides the correct "SameValueZero" comparison needed here.
//                 if (o[k] === searchElement) {
//                     return true;
//                 }
//                 k++;
//             }

//             // 8. Return false
//             return false;
//         }
//     });
// }

// // 方法创建一个新数组，其中包含通过所提供函数实现的测试的所有元素。
// if (!Array.prototype.filter) {
//     Object.defineProperty(Array.prototype, 'filter', {
//         value: function (fun /* , thisArg*/) {

//             if (this === void 0 || this === null)
//                 throw new TypeError();

//             var t = Object(this);
//             var len = t.length >>> 0;
//             if (typeof fun !== 'function')
//                 throw new TypeError();

//             var res = [];
//             var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
//             for (var i = 0; i < len; i++) {
//                 if (i in t) {
//                     var val = t[i];

//                     // NOTE: Technically this should Object.defineProperty at
//                     //       the next index, as push can be affected by
//                     //       properties on Object.prototype and Array.prototype.
//                     //       But that method's new, and collisions should be
//                     //       rare, so use the more-compatible alternative.
//                     if (fun.call(thisArg, val, i, t))
//                         res.push(val);
//                 }
//             }

//             return res;
//         }
//     });
// }

// // 方法测试数组的所有元素是否都通过了指定函数的测试。
// if (!Array.prototype.every) {
//     Object.defineProperty(Array.prototype, 'every', {
//         value: function (fun /*, thisArg */) {

//             if (this === void 0 || this === null)
//                 throw new TypeError();

//             var t = Object(this);
//             var len = t.length >>> 0;
//             if (typeof fun !== 'function')
//                 throw new TypeError();

//             var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
//             for (var i = 0; i < len; i++) {
//                 if (i in t && !fun.call(thisArg, t[i], i, t))
//                     return false;
//             }

//             return true;
//         }
//     });
// }

// // Production steps of ECMA-262, Edition 5, 15.4.4.17
// // Reference: http://es5.github.io/#x15.4.4.17
// // 方法测试数组中的某些元素是否通过由提供的函数实现的测试
// // 对于放在空数组上的任何条件，此方法返回false
// if (!Array.prototype.some) {
//     Object.defineProperty(Array.prototype, 'some', {
//         value: function (fun/*, thisArg*/) {

//             if (this == null) {
//                 throw new TypeError('Array.prototype.some called on null or undefined');
//             }

//             if (typeof fun !== 'function') {
//                 throw new TypeError();
//             }

//             var t = Object(this);
//             var len = t.length >>> 0;

//             var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
//             for (var i = 0; i < len; i++) {
//                 if (i in t && fun.call(thisArg, t[i], i, t)) {
//                     return true;
//                 }
//             }

//             return false;
//         }
//     });
// }

// // Production steps of ECMA-262, Edition 5, 15.4.4.21
// // Reference: http://es5.github.io/#x15.4.4.21
// // https://tc39.github.io/ecma262/#sec-array.prototype.reduce
// if (!Array.prototype.reduce) {
//     Object.defineProperty(Array.prototype, 'reduce', {
//         value: function (callback /*, initialValue*/) {
//             if (this === null) {
//                 throw new TypeError('Array.prototype.reduce ' +
//                     'called on null or undefined');
//             }
//             if (typeof callback !== 'function') {
//                 throw new TypeError(callback +
//                     ' is not a function');
//             }

//             // 1. Let O be ? ToObject(this value).
//             var o = Object(this);

//             // 2. Let len be ? ToLength(? Get(O, "length")).
//             var len = o.length >>> 0;

//             // Steps 3, 4, 5, 6, 7      
//             var k = 0;
//             var value;

//             if (arguments.length >= 2) {
//                 value = arguments[1];
//             } else {
//                 while (k < len && !(k in o)) {
//                     k++;
//                 }

//                 // 3. If len is 0 and initialValue is not present,
//                 //    throw a TypeError exception.
//                 if (k >= len) {
//                     throw new TypeError('Reduce of empty array ' +
//                         'with no initial value');
//                 }
//                 value = o[k++];
//             }

//             // 8. Repeat, while k < len
//             while (k < len) {
//                 // a. Let Pk be ! ToString(k).
//                 // b. Let kPresent be ? HasProperty(O, Pk).
//                 // c. If kPresent is true, then
//                 //    i.  Let kValue be ? Get(O, Pk).
//                 //    ii. Let accumulator be ? Call(
//                 //          callbackfn, undefined,
//                 //          « accumulator, kValue, k, O »).
//                 if (k in o) {
//                     value = callback(value, o[k], k, o);
//                 }

//                 // d. Increase k by 1.      
//                 k++;
//             }

//             // 9. Return accumulator.
//             return value;
//         }
//     });
// }
// if (!Array.prototype.lastIndexOf) {
//     Object.defineProperty(Array.prototype, 'lastIndexOf', {
//         value: function (searchElement /*, fromIndex*/) {
//             if (this === void 0 || this === null) {
//                 throw new TypeError();
//             }

//             var n, k,
//                 t = Object(this),
//                 len = t.length >>> 0;
//             if (len === 0) {
//                 return -1;
//             }

//             n = len - 1;
//             if (arguments.length > 1) {
//                 n = Number(arguments[1]);
//                 if (n != n) {
//                     n = 0;
//                 }
//                 else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
//                     n = (n > 0 || -1) * Math.floor(Math.abs(n));
//                 }
//             }

//             for (k = n >= 0
//                 ? Math.min(n, len - 1)
//                 : len - Math.abs(n); k >= 0; k--) {
//                 if (k in t && t[k] === searchElement) {
//                     return k;
//                 }
//             }
//             return -1;
//         }
//     })
// }

// /********** Object **********/
// if (typeof Object.assign != 'function') {
//     // Must be writable: true, enumerable: false, configurable: true
//     Object.defineProperty(Object, 'assign', {
//         value: function assign(target, varArgs) { // .length of function is 2
//             'use strict';
//             if (target == null) { // TypeError if undefined or null
//                 throw new TypeError('Cannot convert undefined or null to object');
//             }

//             var to = Object(target);

//             for (var index = 1; index < arguments.length; index++) {
//                 var nextSource = arguments[index];

//                 if (nextSource != null) { // Skip over if undefined or null
//                     for (var nextKey in nextSource) {
//                         // Avoid bugs when hasOwnProperty is shadowed
//                         if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
//                             to[nextKey] = nextSource[nextKey];
//                         }
//                     }
//                 }
//             }
//             return to;
//         },
//         writable: true,
//         configurable: true
//     });
// }

// if (typeof Object.create !== 'function') {
//     Object.create = function (proto, propertiesObject) {
//         if (typeof proto !== 'object' && typeof proto !== 'function') {
//             throw new TypeError('Object prototype may only be an Object: ' + proto);
//         } else if (proto === null) {
//             throw new Error('This browser\'s implementation of Object.create is a shim and doesn\'t support \'null\' as the first argument.');
//         }

//         if (typeof propertiesObject != 'undefined') throw new Error('This browser\'s implementation of Object.create is a shim and doesn\'t support a second argument.');

//         function F() { }
//         F.prototype = proto;

//         return new F();
//     };
// }

// if (!Object.keys) {
//     Object.keys = (function () {
//         var hasOwnProperty = Object.prototype.hasOwnProperty,
//             hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
//             dontEnums = [
//                 'toString',
//                 'toLocaleString',
//                 'valueOf',
//                 'hasOwnProperty',
//                 'isPrototypeOf',
//                 'propertyIsEnumerable',
//                 'constructor'
//             ],
//             dontEnumsLength = dontEnums.length;

//         return function (obj) {
//             if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');

//             var result = [];

//             for (var prop in obj) {
//                 if (hasOwnProperty.call(obj, prop)) result.push(prop);
//             }

//             if (hasDontEnumBug) {
//                 for (var i = 0; i < dontEnumsLength; i++) {
//                     if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
//                 }
//             }
//             return result;
//         };
//     })();
// }

// if (!Object.values) {
//     Object.values = function (obj) {
//         if (obj !== Object(obj))
//             throw new TypeError('Object.values called on a non-object');
//         var val = [], key;
//         for (key in obj) {
//             if (Object.prototype.hasOwnProperty.call(obj, key)) {
//                 val.push(obj[key]);
//             }
//         }
//         return val;
//     };
// }

// /********** String **********/
// if (!String.prototype.lastIndexOf) {
//     String.prototype.lastIndexOf = function (searchElement /*, fromIndex*/) {
//         return Array.prototype.lastIndexOf.apply(this, arguments);
//     };
// }

// if (!String.prototype.startsWith) {
//     String.prototype.startsWith = function (searchString, position) {
//         position = position || 0;
//         return this.lastIndexOf(searchString, position) === position;
//     };
// }

// if (!String.prototype.endsWith) {
//     String.prototype.endsWith = function (searchString, position) {
//         if (typeof position === 'undefined' || position > this.length) {
//             position = this.length;
//         }
//         position -= searchString.length;
//         var lastIndex = this.indexOf(searchString, position);
//         return lastIndex !== -1 && lastIndex === position;
//     };
// }
